package zpqy

import (
	"bytes"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"time"

	"github.com/rs/zerolog/log"
	"golang.org/x/sync/semaphore"
)

var (
	// 限制最多同时 10 个 AI 调用
	aiCallSemaphore = semaphore.NewWeighted(1024)
)

type Config struct {
	APIKey      string
	BaseURL     string
	ModelName   string
	HTTPTimeout time.Duration // 单次 HTTP 请求的超时时间
	MaxRetries  int           // 最大重试次数
	RetryDelay  time.Duration // 每次重试之间的延迟
}
type Client struct {
	config Config
}

func NewClient(cfg Config) *Client {
	// 设置默认值
	if cfg.HTTPTimeout <= 0 {
		cfg.HTTPTimeout = 120 * time.Second // 默认 180 秒超时
	}
	if cfg.MaxRetries <= 0 {
		cfg.MaxRetries = 3 // 默认重试 3 次
	}
	if cfg.RetryDelay <= 0 {
		cfg.RetryDelay = 1 * time.Second // 默认延迟 1 秒
	}

	return &Client{config: cfg}
}

func (c *Client) doChatCompletion(ctx context.Context, req *Request) (*Response, error) {
	apiURL := c.config.BaseURL + "/chat/completions"

	// 序列化请求体
	body, err := json.Marshal(req)
	if err != nil {
		log.Error().Err(err).Msg("Failed to marshal request body")
		return nil, fmt.Errorf("failed to marshal request: %w", err)
	}

	// 创建 HTTP 请求，并传入 context
	httpReq, err := http.NewRequestWithContext(ctx, "POST", apiURL, bytes.NewBuffer(body))
	if err != nil {
		log.Error().Err(err).Msg("Failed to create HTTP request")
		return nil, fmt.Errorf("failed to create request: %w", err)
	}

	// 设置请求头
	httpReq.Header.Set("Authorization", "Bearer "+c.config.APIKey)
	httpReq.Header.Set("Content-Type", "application/json")

	log.Debug().Str("url", apiURL).RawJSON("request_body", body).Msg("Sending request to AI API")

	// 创建一个带超时的 HTTP 客户端
	client := &http.Client{Timeout: c.config.HTTPTimeout}
	resp, err := client.Do(httpReq)
	if err != nil {
		// 检查错误是否由 context 的超时或取消导致
		if errors.Is(err, context.DeadlineExceeded) {
			log.Error().Err(err).Dur("timeout", c.config.HTTPTimeout).Msg("Request timed out")
		} else {
			log.Error().Err(err).Msg("Failed to send request to AI API")
		}
		return nil, fmt.Errorf("request failed: %w", err)
	}
	defer resp.Body.Close()

	log.Debug().Int("status_code", resp.StatusCode).Msg("Received response from AI API")

	if resp.StatusCode != http.StatusOK {
		// 读取并记录错误响应体
		errorBodyBytes, readErr := io.ReadAll(resp.Body)
		if readErr != nil {
			log.Error().Err(readErr).Msg("Failed to read error response body from API")
		} else {
			log.Error().
				Int("status_code", resp.StatusCode).
				RawJSON("response_body", errorBodyBytes).
				Msg("API returned non-OK status")
		}
		return nil, fmt.Errorf("API error: %s (status: %d)", resp.Status, resp.StatusCode)
	}
	// 解析响应
	var result Response
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		log.Error().Err(err).Msg("Failed to decode AI API response")
		return nil, fmt.Errorf("failed to decode response: %w", err)
	}

	// 检查是否有返回内容
	if len(result.Choices) == 0 {
		log.Warn().Msg("AI API returned a response with no choices")
		return nil, errors.New("no response from model")
	}

	log.Debug().Int("choices_count", len(result.Choices)).Msg("Successfully parsed AI response")
	return &result, nil
}

func (c *Client) ChatCompletion(ctx context.Context, userInput, sysInput string) (<-chan *Response, error) {
	// 创建一个带缓冲的 channel，用于返回结果。
	// 缓冲为1，确保发送方（内部goroutine）在发送后不会阻塞，即使接收方已经不再监听。
	if err := aiCallSemaphore.Acquire(ctx, 1); err != nil {
		return nil, fmt.Errorf("failed to acquire AI call semaphore: %w", err)
	}
	defer aiCallSemaphore.Release(1) // 确保调用完成后释放信号量

	resultChan := make(chan *Response, 1)

	// 准备请求体
	req := c.NewDefaultRequest()
	req.SetSystemMessage(sysInput)
	req.SetUserMessage(userInput)

	// 启动一个新的 Goroutine 来执行耗时和可能重试的操作。
	// 这使得 ChatCompletion 方法本身可以立即返回，实现非阻塞。
	go func() {
		// 使用 defer 来确保 channel 在任何情况下都会被关闭。
		// 这是一个好习惯，可以防止接收方（比如HTTP handler）永久阻塞。
		defer close(resultChan)

		var lastErr error
		for i := 0; i < c.config.MaxRetries; i++ {
			// 每次尝试前，检查 context 是否已取消
			if err := ctx.Err(); err != nil {
				log.Warn().Err(err).Msg("Context cancelled before AI request attempt")
				// 不需要发送错误到 channel，因为关闭的 channel 和 context.Err() 本身就足够了
				return
			}

			if i > 0 {
				log.Warn().Err(lastErr).Int("attempt", i+1).Dur("delay", c.config.RetryDelay).Msg("Retrying AI request")
				// 在重试前等待，同时检查 context 是否已取消
				select {
				case <-time.After(c.config.RetryDelay):
					// 等待结束，继续下一次尝试
				case <-ctx.Done():
					log.Warn().Err(ctx.Err()).Msg("Context cancelled during retry delay")
					return
				}
			}

			// 执行单次请求
			resp, err := c.doChatCompletion(ctx, req)
			if err == nil {
				// 成功！将结果发送到 channel
				resultChan <- resp
				return // 成功后立即退出 Goroutine
			}
			// 记录本次失败，准备下一次重试
			lastErr = err
			log.Error().Err(err).Int("attempt", i+1).Msg("AI request attempt failed")
		}

		// 如果循环结束，说明所有重试都失败了
		log.Error().Err(lastErr).Int("max_retries", c.config.MaxRetries).Msg("All retries for AI request failed")
		// 我们不发送错误到 channel，因为 channel 的类型是 `chan *Response`。
		// 调用方通过读取到 nil 值（在 channel 关闭后）和检查 context 状态来判断失败。
	}()

	// 立即返回 channel，实现非阻塞
	return resultChan, nil
}

func (c *Client) NewDefaultRequest() *Request {
	return &Request{
		Model:       c.config.ModelName,
		MaxTokens:   2048,
		Temperature: 0.6,
		Stream:      false,
		Messages:    make([]Message, 0),
	}
}
